unit fpreports;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, serverUtils, Sqlite3DS, hpdf, hpdf_types, fposUtils;

procedure DrawText( canvas: HPDF_Page; x, y, w: Double; fontName: PChar; fontsize: Integer; txt: PChar; justify: Integer; underline:Boolean);
function ShiftReport( var pdf: HPDF_Doc; terminalID: integer;  checksum: string): Integer;

const
   JUSTIFY_LEFT   = 0;
   JUSTIFY_CENTER = 1;
   JUSTIFY_RIGHT  = 2;


implementation

procedure DrawText ( canvas: HPDF_Page; x, y, w: Double; fontName: PChar;
  fontsize: Integer; txt: PChar; justify: Integer; underline: Boolean ) ;
var
  ln: Integer;
  rw: Single;
  lx: Double;
begin
  lx := x;
  // Set font
  HPDF_Page_SetFontAndSize(canvas, fontName, fontSize);

  HPDF_Page_BeginText(canvas);

  // Truncate the text to max col width
  ln := HPDF_Page_MeasureText(canvas, txt, w, 0, @rw);
//  MID$(txt, ln+1) = CHR$(0)

  // Justify
  IF justify = JUSTIFY_RIGHT THEN
      // Right justify the text
      lx := x + (w - rw)
  ELSE IF justify = JUSTIFY_CENTER THEN
      // Center justify the text
      lx := x + (w - rw) / 2;

  // Draw the text
  HPDF_Page_MoveTextPos(canvas, lx, y);
  HPDF_Page_ShowText(canvas, txt);
  HPDF_Page_EndText(canvas);

  // Underline the text if flag is set
  IF underline THEN
      begin
      HPDF_Page_MoveTo(canvas, x, y-1);
      HPDF_Page_LineTo(canvas, x + w, y-1);
      HPDF_Page_Stroke(canvas);
      end;
end;

function ShiftReport ( var pdf: HPDF_Doc; terminalID: integer; checksum: string) : Integer;
var
  DB: TSQLDataset;
  page: HPDF_Page;
  pages: TList;
  samp_text: String;
  afont: HPDF_Font;
  aheight: HPDF_REAL;
  awidth: HPDF_REAL;
  def_font: HPDF_Font;
  tw: HPDF_REAL;
  page_title: String;
  i: Integer;
  SQL: String;
  tx: String;
  p: THPDF_Point;
  tab0: Integer;
  tab1: Integer;
  tab2: Integer;
  tab3: Integer;
  startsaleid: Integer;
  endsaleid: Integer;
  salenum: Integer;
  sn: Integer;
  tot: Double;
  x: Integer;
  line_y: Single;
  starttime: TDateTime;
  line_y_marker: Single;

  procedure NewPage;
  begin
    page := HPDF_AddPage (pdf);
    pages.Add(page);
    line_y := aheight-60;
  end;

  procedure WriteTotal;
  begin
    DrawText(page, tab2, line_y, 55, def_font, 10, PChar('Total:'), JUSTIFY_RIGHT, false);
    DrawText(page, tab3, line_y, 60, def_font, 10, PChar(FormatFloat('0.00', tot)), JUSTIFY_RIGHT, false);
    HPDF_Page_MoveTo(page, tab0, line_y-3);
    HPDF_Page_LineTo(page, tab3 + 60, line_y-3);
    HPDF_Page_Stroke(page);
  end;

begin
  Result := -1;
  DB := TSQLDataset.Create(nil);
  DB.FileName := SYSTEMDB;
  DB.ExecSQL('ATTACH "' + SALESDB + '" AS salesdb;' );
  DB.TableName := 'Terminals';
  SQL := 'SELECT staffid, startcash, endcash, starttime, endtime, startsaleid, endsaleid FROM Shifts WHERE TerminalID=' + IntToStr(terminalID)
          + ' AND checksum="' + checksum +'";';
{$IFDEF DEBUG}   writeln(SQL);     {$ENDIF}
  DB.SQL := SQL;
  DB.Open;
  if DB.RecordCount<1 then begin writeln('Shift not found'); Exit; end;
  tot := 0;
  starttime :=0.0;
  starttime := JulianDateTimeToDateTime( DB.FieldByName('starttime').AsFloat );
  startsaleid := DB.FieldByName('startsaleid').AsInteger;
  endsaleid := DB.FieldByName('endsaleid').AsInteger;
  if endsaleid<startsaleid then endsaleid := (terminalID*1000000)+999999;
  pages := TList.Create;
  HPDF_SetInfoAttr(pdf, HPDF_INFO_TITLE, PChar('Shift Report ' + FormatDateTime('dddd d mmm yyyy', starttime )));
  def_font := HPDF_GetFont(pdf, Pchar('Helvetica'), nil);
  page := HPDF_AddPage (pdf);

  page_title := 'Shift Report';
  aheight := HPDF_Page_GetHeight (page);
  awidth := HPDF_Page_GetWidth (page);
  def_font := HPDF_GetFont (pdf, PChar('Helvetica'), nil);
  HPDF_Page_SetFontAndSize (page, def_font, 20);
  tw := HPDF_Page_TextWidth (page, PChar(page_title));
  HPDF_Page_BeginText (page);
  HPDF_Page_TextOut (page, (awidth - tw) / 2, aheight - 60, PChar(page_title));
  HPDF_Page_EndText (page);

  line_y := aheight-90;
  tab0 := 60;
  tab1 := 150;

  DrawText(page, tab0, line_y, 100, def_font, 10, PChar('Date:'), JUSTIFY_LEFT, false);
  DrawText(page, tab1, line_y, 100, def_font, 10, PChar(FormatDateTime('dddd d mmm yyyy', starttime )), JUSTIFY_LEFT, false);
  line_y := line_y - 16;

  DrawText(page, tab0, line_y, 100, def_font, 10, PChar('Terminal ID:'), JUSTIFY_LEFT, false);
  DrawText(page, tab1, line_y, 100, def_font, 10, PChar(IntToStr(terminalID)), JUSTIFY_LEFT, false);
  line_y := line_y - 12;

  DrawText(page, tab0, line_y, 100, def_font, 10, PChar('Operator ID:'), JUSTIFY_LEFT, false);
  DrawText(page, tab1, line_y, 100, def_font, 10, PChar(DB.FieldByName('staffid'). AsString ), JUSTIFY_LEFT, false);
  line_y := line_y - 16;

  DrawText(page, tab0, line_y, 100, def_font, 10, PChar('Shift start:'), JUSTIFY_LEFT, false);
  DrawText(page, tab1, line_y, 100, def_font, 10, PChar(FormatDateTime('d mmm yyyy  hh:nn', starttime )), JUSTIFY_LEFT, false);
  line_y := line_y - 12;

  DrawText(page, tab0, line_y, 100, def_font, 10, PChar('Shift end'), JUSTIFY_LEFT, false);
  if not DB.FieldByName('endtime').IsNull
     then DrawText(page, tab1, line_y, 100, def_font, 10, PChar(FormatJulianDateTime('d mmm yyyy  hh:nn', DB.FieldByName('endtime').AsFloat )), JUSTIFY_LEFT, false);
  line_y := line_y - 16;

  line_y_marker := line_y;
  DrawText(page, tab0, line_y, 100, def_font, 10, PChar('Total receipts:'), JUSTIFY_LEFT, false);
  //DrawText(page, tab1, line_y, 100, def_font, 10, PChar(FormatFloat('0.00', tot )), JUSTIFY_LEFT, false);
  line_y := line_y - 30;

  DB.Close;

  SQL := 'SELECT Departments.name AS deptname, SUM(subtotal) AS subtotal, SUM(sales) AS sales FROM Departments'
          + ' LEFT JOIN (SELECT dept, TOTAL(price) AS subtotal, SUM(quantity) AS sales FROM saledetails, products '
          + ' WHERE itemID=productID AND saleid>' + IntToStr(startsaleid)
          + ' AND saleid<=' + IntToStr(endsaleid) + ' GROUP BY dept ) ON Departments.id=dept GROUP BY deptname ORDER BY Departments.id;';
  writeln(SQL);
  DB.SQL := SQL;
  DB.Open;
  if DB.RecordCount<1 then Exit;
  tab0 := 60;
  tab1 := 150;
  tab2 := 180;

  DrawText(page, tab0, line_y, 150, def_font, 10, PChar('Department'), JUSTIFY_LEFT, false);
  DrawText(page, tab1, line_y, 100, def_font, 10, PChar('Sales'), JUSTIFY_CENTER, false);
  DrawText(page, tab2, line_y, 100, def_font, 10, PChar('Subtotal'), JUSTIFY_RIGHT, false);
  HPDF_Page_MoveTo(page, tab0, line_y-1);
  HPDF_Page_LineTo(page, tab2 + 100, line_y-1);
  HPDF_Page_Stroke(page);

  line_y := line_y - 12;

  while not DB.EOF do
        begin
          tx := DB.FieldByName('deptname').AsString ;
          DrawText(page, tab0, line_y, 130, def_font, 10, PChar(tx), JUSTIFY_LEFT, false);

          tx := DB.FieldByName('sales').AsString ;
          DrawText(page, tab1, line_y, 100, def_font, 10, PChar(tx), JUSTIFY_CENTER, false);

          if DB.FieldByName('subtotal').IsNull
             then tx := '0.00'
             else
               begin
                 tx := FormatFloat('0.00', DB.FieldByName('subtotal').AsFloat);
                 tot := tot + DB.FieldByName('subtotal').AsFloat;
               end;
          DrawText(page, tab2, line_y, 100, def_font, 10, PChar(tx), JUSTIFY_RIGHT, false);

          line_y := line_y-12;
          DB.Next;
        end;
  DrawText(page, tab1, line_y_marker, 100, def_font, 10, PChar(FormatFloat('0.00', tot )), JUSTIFY_LEFT, false);
  DB.Close;

  HPDF_Page_MoveTo(page, tab0, line_y);
  HPDF_Page_LineTo(page, awidth-120, line_y);
  HPDF_Page_Stroke(page);

  SQL := 'SELECT saledetails.saleid AS saleid, saletime, total, products.name AS itemname, quantity, price FROM saledetails, salesummary, products '
          + 'WHERE saledetails.saleid=salesummary.saleID AND products.productID=saledetails.itemID '
          + ' AND saledetails.saleid>' + IntToStr(startsaleid)
          + ' AND saledetails.saleid<=' + IntToStr(endsaleid) + ';';
  writeln(SQL);
  DB.SQL := SQL;
  DB.Open;

  tab1 := 100;
  tab2 := 300;
  tab3 := 360;

  line_y := line_y-10;

  salenum := 0;
  while not DB.EOF do
        begin
          sn := DB.FieldByName('saleid').AsInteger;
          if sn>salenum then
              begin
                if DB.RecNo>1
                   then WriteTotal;
                salenum := sn;
                tot := DB.FieldByName('total').AsFloat;
                line_y := line_y-20;

                tx := DB.FieldByName('saleid').AsString
                      + FormatJulianDateTime('   d mmm yyy  hh:nn', DB.FieldByName('saletime').AsFloat);
                DrawText(page, tab0, line_y, 400, def_font, 10, PChar(tx), JUSTIFY_LEFT, false);
                line_y := line_y-12;
              end;
          tx := DB.FieldByName('itemname').AsString;
          DrawText(page, tab1, line_y, 145, def_font, 10, PChar(tx), JUSTIFY_LEFT, false);

          if DB.FieldByName('quantity').AsInteger>0
             then tx := ' x'  + DB.FieldByName('quantity').AsString;
          DrawText(page, tab2, line_y, 55, def_font, 10, PChar(tx), JUSTIFY_RIGHT, false);

          if DB.FieldByName('price').IsNull
             then tx := '0.00'
          else tx := FormatFloat('0.00', DB.FieldByName('price').AsFloat);
          DrawText(page, tab3, line_y, 60, def_font, 10, PChar(tx), JUSTIFY_RIGHT, false);
          line_y := line_y-12;
          DB.Next;
          if line_y<60 then NewPage;
        end;
  if DB.RecordCount>0 then WriteTotal;

  for x := 0 to pages.Count-1 do
      begin
        page := HPDF_Page(Pages[x]);
        tx := 'Terminal ' + IntToStr(terminalID) + ' - Shift Report ' + FormatDateTime('dd/mm/yy hh:nn', starttime)
               + '   Page ' + IntToStr(x+2) + ' of ' + IntToStr(Pages.Count+1);
        DrawText(page, tab0, aheight-40, awidth-120, def_font, 10, PChar(tx), JUSTIFY_RIGHT, false);
      end;

  HPDF_SaveToStream(pdf);
  Pages.Free;
  Result := HPDF_GetStreamSize(pdf);
end;

end.

